home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / ucbmail / cmd3.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-06-03  |  15.4 KB  |  862 lines

  1. /*
  2.  *  C M D 3 . C 
  3.  *
  4.  *  EE/CIS Computer Lab
  5.  *  Department of Computer and Information Sciences
  6.  *  Department of Electrical Engineering
  7.  *  University of Delaware
  8.  *
  9.  *  REVISION HISTORY:
  10.  *
  11.  *  $Revision: 1.3 $
  12.  *
  13.  *  $Log:    cmd3.c,v $
  14.  * Revision 1.3  86/01/14  14:16:30  galvin
  15.  * respond() needed some tuning.  Basically, we use a Reply-To over
  16.  * the From or Sender.  Also, we reply to all address, to and cc, even
  17.  * if we find a Reply-To.  Previously, the existance of a Reply-To
  18.  * caused respond() to behave like Respond().  Change delname() to use
  19.  * routeq() and eliminate a couple skin()'s since MMDF likes full names.
  20.  * Finally make sure we delimit addresses by "," where appropriate.
  21.  * 
  22.  * In Respond(), remove the skin() call and delimit addresses by ",".
  23.  * 
  24.  * Revision 1.2  86/01/07  13:53:36  galvin
  25.  * Added comment header for revision history.
  26.  * 
  27.  *
  28.  */
  29.  
  30. /*
  31.  * Copyright (c) 1980 Regents of the University of California.
  32.  * All rights reserved.  The Berkeley software License Agreement
  33.  * specifies the terms and conditions for redistribution.
  34.  */
  35.  
  36. #ifndef lint
  37. static char *sccsid = "@(#)cmd3.c    5.2 (Berkeley) 6/21/85";
  38. #endif not lint
  39.  
  40. #include "./rcv.h"
  41. #include <sys/stat.h>
  42.  
  43. /*
  44.  * Mail -- a mail program
  45.  *
  46.  * Still more user commands.
  47.  */
  48.  
  49. /*
  50.  * Process a shell escape by saving signals, ignoring signals,
  51.  * and forking a sh -c
  52.  */
  53.  
  54. shell(str)
  55.     char *str;
  56. {
  57.     int (*sig[2])(), stat[1];
  58.     register int t;
  59.     char *Shell;
  60.     char cmd[BUFSIZ];
  61.  
  62.     strcpy(cmd, str);
  63.     if (bangexp(cmd) < 0)
  64.         return(-1);
  65.     if ((Shell = value("SHELL")) == NOSTR)
  66.         Shell = SHELL;
  67.     for (t = 2; t < 4; t++)
  68.         sig[t-2] = sigset(t, SIG_IGN);
  69.     t = vfork();
  70.     if (t == 0) {
  71.         sigchild();
  72.         for (t = 2; t < 4; t++)
  73.             if (sig[t-2] != SIG_IGN)
  74.                 sigsys(t, SIG_DFL);
  75.         execl(Shell, Shell, "-c", cmd, 0);
  76.         perror(Shell);
  77.         _exit(1);
  78.     }
  79.     while (wait(stat) != t)
  80.         ;
  81.     if (t == -1)
  82.         perror("fork");
  83.     for (t = 2; t < 4; t++)
  84.         sigset(t, sig[t-2]);
  85.     printf("!\n");
  86.     return(0);
  87. }
  88.  
  89. /*
  90.  * Fork an interactive shell.
  91.  */
  92.  
  93. dosh()
  94. {
  95.     int (*sig[2])(), stat[1];
  96.     register int t;
  97.     char *Shell;
  98.     if ((Shell = value("SHELL")) == NOSTR)
  99.         Shell = SHELL;
  100.     for (t = 2; t < 4; t++)
  101.         sig[t-2] = sigset(t, SIG_IGN);
  102.     t = vfork();
  103.     if (t == 0) {
  104.         sigchild();
  105.         for (t = 2; t < 4; t++)
  106.             if (sig[t-2] != SIG_IGN)
  107.                 sigsys(t, SIG_DFL);
  108.         execl(Shell, Shell, 0);
  109.         perror(Shell);
  110.         _exit(1);
  111.     }
  112.     while (wait(stat) != t)
  113.         ;
  114.     if (t == -1)
  115.         perror("fork");
  116.     for (t = 2; t < 4; t++)
  117.         sigsys(t, sig[t-2]);
  118.     putchar('\n');
  119.     return(0);
  120. }
  121.  
  122. /*
  123.  * Expand the shell escape by expanding unescaped !'s into the
  124.  * last issued command where possible.
  125.  */
  126.  
  127. char    lastbang[128];
  128.  
  129. bangexp(str)
  130.     char *str;
  131. {
  132.     char bangbuf[BUFSIZ];
  133.     register char *cp, *cp2;
  134.     register int n;
  135.     int changed = 0;
  136.  
  137.     cp = str;
  138.     cp2 = bangbuf;
  139.     n = BUFSIZ;
  140.     while (*cp) {
  141.         if (*cp == '!') {
  142.             if (n < strlen(lastbang)) {
  143. overf:
  144.                 printf("Command buffer overflow\n");
  145.                 return(-1);
  146.             }
  147.             changed++;
  148.             strcpy(cp2, lastbang);
  149.             cp2 += strlen(lastbang);
  150.             n -= strlen(lastbang);
  151.             cp++;
  152.             continue;
  153.         }
  154.         if (*cp == '\\' && cp[1] == '!') {
  155.             if (--n <= 1)
  156.                 goto overf;
  157.             *cp2++ = '!';
  158.             cp += 2;
  159.             changed++;
  160.         }
  161.         if (--n <= 1)
  162.             goto overf;
  163.         *cp2++ = *cp++;
  164.     }
  165.     *cp2 = 0;
  166.     if (changed) {
  167.         printf("!%s\n", bangbuf);
  168.         fflush(stdout);
  169.     }
  170.     strcpy(str, bangbuf);
  171.     strncpy(lastbang, bangbuf, 128);
  172.     lastbang[127] = 0;
  173.     return(0);
  174. }
  175.  
  176. /*
  177.  * Print out a nice help message from some file or another.
  178.  */
  179.  
  180. help()
  181. {
  182.     register c;
  183.     register FILE *f;
  184.  
  185.     if ((f = fopen(HELPFILE, "r")) == NULL) {
  186.         perror(HELPFILE);
  187.         return(1);
  188.     }
  189.     while ((c = getc(f)) != EOF)
  190.         putchar(c);
  191.     fclose(f);
  192.     return(0);
  193. }
  194.  
  195. /*
  196.  * Change user's working directory.
  197.  */
  198.  
  199. schdir(str)
  200.     char *str;
  201. {
  202.     register char *cp;
  203.  
  204.     for (cp = str; *cp == ' '; cp++)
  205.         ;
  206.     if (*cp == '\0')
  207.         cp = homedir;
  208.     else
  209.         if ((cp = expand(cp)) == NOSTR)
  210.             return(1);
  211.     if (chdir(cp) < 0) {
  212.         perror(cp);
  213.         return(1);
  214.     }
  215.     return(0);
  216. }
  217.  
  218. /*
  219.  * Reply to a list of messages.  Extract each name from the
  220.  * message header and send them off to mail1()
  221.  *
  222.  * What we want is to use a Reply-To field over the sender/from,
  223.  * and to include all To and Cc recipients.  Previously the existence
  224.  * of a Reply-To would behave as if "R" was used instead of "r".
  225.  * This is inconsistent with MMDF.
  226.  */
  227.  
  228. respond(msgvec)
  229.     int *msgvec;
  230. {
  231.     struct message *mp;
  232.     char *cp, *rcv, *replyto;
  233.     char buf[2 * LINESIZE], **ap;
  234.     struct name *np;
  235.     struct header head;
  236.  
  237.     if (msgvec[1] != 0) {
  238.         printf("Sorry, can't reply to multiple messages at once\n");
  239.         return(1);
  240.     }
  241.     mp = &message[msgvec[0] - 1];
  242.     dot = mp;
  243.     rcv = NOSTR;
  244.     cp = nameof(mp, 1);
  245.     if (cp != NOSTR && *cp)
  246.         rcv = cp;
  247.     cp = hfield("from", mp);
  248.     if (cp != NOSTR && *cp)
  249.         rcv = cp;
  250.     replyto = hfield("reply-to", mp);
  251.     if (replyto != NOSTR && *replyto)
  252.         strcpy(buf, replyto);
  253.     else if (rcv != NOSTR && *rcv)
  254.         strcpy(buf, rcv);
  255.     else
  256.         strcpy(buf, "");
  257.     cp = hfield("to", mp);
  258.     if (cp != NOSTR && *cp && *buf) {
  259.         strcat(buf, ", ");
  260.         strcat(buf, cp);
  261.     }
  262.     else if (cp != NOSTR)
  263.         strcpy(buf, cp);
  264.     np = elide(extract(buf, GTO));
  265.     mapf(np, rcv);
  266.     /*
  267.      * Delete my name from the reply list,
  268.      * and with it, all my alternate names.
  269.      */
  270.     np = delname(np, myname, routeq);
  271.     if (altnames)
  272.         for (ap = altnames; *ap; ap++)
  273.             np = delname(np, *ap, routeq);
  274.     head.h_seq = 1;
  275.     cp = detract(np, 0);
  276.     head.h_to = NOSTR;
  277.     if (cp != NOSTR)
  278.         head.h_to = cp;
  279.         else
  280.         printf("Empty To field -- hope that's ok.\n");
  281.     head.h_subject = hfield("subject", mp);
  282.     if (head.h_subject == NOSTR)
  283.         head.h_subject = hfield("subj", mp);
  284.     head.h_subject = reedit(head.h_subject);
  285.     head.h_cc = NOSTR;
  286.         cp = hfield("cc", mp);
  287.         if (cp != NOSTR) {
  288.             np = elide(extract(cp, GCC));
  289.             mapf(np, rcv);
  290.         np = delname(np, myname, routeq);
  291.             if (altnames != 0)
  292.                 for (ap = altnames; *ap; ap++)
  293.                 np = delname(np, *ap, routeq);
  294.             head.h_cc = detract(np, 0);
  295.         }
  296.     head.h_bcc = NOSTR;
  297.     mail1(&head);
  298.     return(0);
  299. }
  300.  
  301. /*
  302.  * Modify the subject we are replying to to begin with Re: if
  303.  * it does not already.
  304.  */
  305.  
  306. char *
  307. reedit(subj)
  308.     char *subj;
  309. {
  310.     char sbuf[10];
  311.     register char *newsubj;
  312.  
  313.     if (subj == NOSTR)
  314.         return(NOSTR);
  315.     strncpy(sbuf, subj, 3);
  316.     sbuf[3] = 0;
  317.     if (icequal(sbuf, "re:"))
  318.         return(subj);
  319.     newsubj = salloc(strlen(subj) + 6);
  320.     sprintf(newsubj, "Re:  %s", subj);
  321.     return(newsubj);
  322. }
  323.  
  324. /*
  325.  * Preserve the named messages, so that they will be sent
  326.  * back to the system mailbox.
  327.  */
  328.  
  329. preserve(msgvec)
  330.     int *msgvec;
  331. {
  332.     register struct message *mp;
  333.     register int *ip, mesg;
  334.  
  335.     if (edit) {
  336.         printf("Cannot \"preserve\" in edit mode\n");
  337.         return(1);
  338.     }
  339.     for (ip = msgvec; *ip != NULL; ip++) {
  340.         mesg = *ip;
  341.         mp = &message[mesg-1];
  342.         mp->m_flag |= MPRESERVE;
  343.         mp->m_flag &= ~MBOX;
  344.         dot = mp;
  345.     }
  346.     return(0);
  347. }
  348.  
  349. /*
  350.  * Mark all given messages as unread.
  351.  */
  352. unread(msgvec)
  353.     int    msgvec[];
  354. {
  355.     register int *ip;
  356.  
  357.     for (ip = msgvec; *ip != NULL; ip++) {
  358.         dot = &message[*ip-1];
  359.         dot->m_flag &= ~(MREAD|MTOUCH);
  360.         dot->m_flag |= MSTATUS;
  361.     }
  362.     return(0);
  363. }
  364.  
  365. /*
  366.  * Print the size of each message.
  367.  */
  368.  
  369. messize(msgvec)
  370.     int *msgvec;
  371. {
  372.     register struct message *mp;
  373.     register int *ip, mesg;
  374.  
  375.     for (ip = msgvec; *ip != NULL; ip++) {
  376.         mesg = *ip;
  377.         mp = &message[mesg-1];
  378.         printf("%d: %ld\n", mesg, mp->m_size);
  379.     }
  380.     return(0);
  381. }
  382.  
  383. /*
  384.  * Quit quickly.  If we are sourcing, just pop the input level
  385.  * by returning an error.
  386.  */
  387.  
  388. rexit(e)
  389. {
  390.     if (sourcing)
  391.         return(1);
  392.     if (Tflag != NOSTR)
  393.         close(creat(Tflag, 0600));
  394.     exit(e);
  395.     /*NOTREACHED*/
  396. }
  397.  
  398. /*
  399.  * Set or display a variable value.  Syntax is similar to that
  400.  * of csh.
  401.  */
  402.  
  403. set(arglist)
  404.     char **arglist;
  405. {
  406.     register struct var *vp;
  407.     register char *cp, *cp2;
  408.     char varbuf[BUFSIZ], **ap, **p;
  409.     int errs, h, s;
  410.  
  411.     if (argcount(arglist) == 0) {
  412.         for (h = 0, s = 1; h < HSHSIZE; h++)
  413.             for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
  414.                 s++;
  415.         ap = (char **) salloc(s * sizeof *ap);
  416.         for (h = 0, p = ap; h < HSHSIZE; h++)
  417.             for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
  418.                 *p++ = vp->v_name;
  419.         *p = NOSTR;
  420.         sort(ap);
  421.         for (p = ap; *p != NOSTR; p++)
  422.             printf("%s\t%s\n", *p, value(*p));
  423.         return(0);
  424.     }
  425.     errs = 0;
  426.     for (ap = arglist; *ap != NOSTR; ap++) {
  427.         cp = *ap;
  428.         cp2 = varbuf;
  429.         while (*cp != '=' && *cp != '\0')
  430.             *cp2++ = *cp++;
  431.         *cp2 = '\0';
  432.         if (*cp == '\0')
  433.             cp = "";
  434.         else
  435.             cp++;
  436.         if (equal(varbuf, "")) {
  437.             printf("Non-null variable name required\n");
  438.             errs++;
  439.             continue;
  440.         }
  441.         assign(varbuf, cp);
  442.     }
  443.     return(errs);
  444. }
  445.  
  446. /*
  447.  * Unset a bunch of variable values.
  448.  */
  449.  
  450. unset(arglist)
  451.     char **arglist;
  452. {
  453.     register struct var *vp, *vp2;
  454.     int errs, h;
  455.     char **ap;
  456.  
  457.     errs = 0;
  458.     for (ap = arglist; *ap != NOSTR; ap++) {
  459.         if ((vp2 = lookup(*ap)) == NOVAR) {
  460.             if (!sourcing) {
  461.                 printf("\"%s\": undefined variable\n", *ap);
  462.                 errs++;
  463.             }
  464.             continue;
  465.         }
  466.         h = hash(*ap);
  467.         if (vp2 == variables[h]) {
  468.             variables[h] = variables[h]->v_link;
  469.             vfree(vp2->v_name);
  470.             vfree(vp2->v_value);
  471.             cfree((char *) vp2);
  472.             continue;
  473.         }
  474.         for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link)
  475.             ;
  476.         vp->v_link = vp2->v_link;
  477.         vfree(vp2->v_name);
  478.         vfree(vp2->v_value);
  479.         cfree((char *) vp2);
  480.     }
  481.     return(errs);
  482. }
  483.  
  484. /*
  485.  * Put add users to a group.
  486.  */
  487.  
  488. group(argv)
  489.     char **argv;
  490. {
  491.     register struct grouphead *gh;
  492.     register struct group *gp;
  493.     register int h;
  494.     int s;
  495.     char **ap, *gname, **p;
  496.  
  497.     if (argcount(argv) == 0) {
  498.         for (h = 0, s = 1; h < HSHSIZE; h++)
  499.             for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
  500.                 s++;
  501.         ap = (char **) salloc(s * sizeof *ap);
  502.         for (h = 0, p = ap; h < HSHSIZE; h++)
  503.             for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
  504.                 *p++ = gh->g_name;
  505.         *p = NOSTR;
  506.         sort(ap);
  507.         for (p = ap; *p != NOSTR; p++)
  508.             printgroup(*p);
  509.         return(0);
  510.     }
  511.     if (argcount(argv) == 1) {
  512.         printgroup(*argv);
  513.         return(0);
  514.     }
  515.     gname = *argv;
  516.     h = hash(gname);
  517.     if ((gh = findgroup(gname)) == NOGRP) {
  518.         gh = (struct grouphead *) calloc(sizeof *gh, 1);
  519.         gh->g_name = vcopy(gname);
  520.         gh->g_list = NOGE;
  521.         gh->g_link = groups[h];
  522.         groups[h] = gh;
  523.     }
  524.  
  525.     /*
  526.      * Insert names from the command list into the group.
  527.      * Who cares if there are duplicates?  They get tossed
  528.      * later anyway.
  529.      */
  530.  
  531.     for (ap = argv+1; *ap != NOSTR; ap++) {
  532.         gp = (struct group *) calloc(sizeof *gp, 1);
  533.         gp->ge_name = vcopy(*ap);
  534.         gp->ge_link = gh->g_list;
  535.         gh->g_list = gp;
  536.     }
  537.     return(0);
  538. }
  539.  
  540. /*
  541.  * Sort the passed string vecotor into ascending dictionary
  542.  * order.
  543.  */
  544.  
  545. sort(list)
  546.     char **list;
  547. {
  548.     register char **ap;
  549.     int diction();
  550.  
  551.     for (ap = list; *ap != NOSTR; ap++)
  552.         ;
  553.     if (ap-list < 2)
  554.         return;
  555.     qsort((char *) list, ap-list, sizeof *list, diction);
  556. }
  557.  
  558. /*
  559.  * Do a dictionary order comparison of the arguments from
  560.  * qsort.
  561.  */
  562.  
  563. diction(a, b)
  564.     register char **a, **b;
  565. {
  566.     return(strcmp(*a, *b));
  567. }
  568.  
  569. /*
  570.  * The do nothing command for comments.
  571.  */
  572.  
  573. null()
  574. {
  575.     return(0);
  576. }
  577.  
  578. /*
  579.  * Print out the current edit file, if we are editing.
  580.  * Otherwise, print the name of the person who's mail
  581.  * we are reading.
  582.  */
  583.  
  584. file(argv)
  585.     char **argv;
  586. {
  587.     register char *cp;
  588.     int ed;
  589.  
  590.     if (argv[0] == NOSTR) {
  591.         newfileinfo();
  592.         return(0);
  593.     }
  594.  
  595.     /*
  596.      * Acker's!  Must switch to the new file.
  597.      * We use a funny interpretation --
  598.      *    # -- gets the previous file
  599.      *    % -- gets the invoker's post office box
  600.      *    %user -- gets someone else's post office box
  601.      *    & -- gets invoker's mbox file
  602.      *    string -- reads the given file
  603.      */
  604.  
  605.     cp = getfilename(argv[0], &ed);
  606.     if (cp == NOSTR)
  607.         return(-1);
  608.     if (setfile(cp, ed)) {
  609.         perror(cp);
  610.         return(-1);
  611.     }
  612.     newfileinfo();
  613.     return(0);
  614. }
  615.  
  616. /*
  617.  * Evaluate the string given as a new mailbox name.
  618.  * Ultimately, we want this to support a number of meta characters.
  619.  * Possibly:
  620.  *    % -- for my system mail box
  621.  *    %user -- for user's system mail box
  622.  *    # -- for previous file
  623.  *    & -- get's invoker's mbox file
  624.  *    file name -- for any other file
  625.  */
  626.  
  627. char    prevfile[PATHSIZE];
  628.  
  629. char *
  630. getfilename(name, aedit)
  631.     char *name;
  632.     int *aedit;
  633. {
  634.     register char *cp;
  635.     char savename[BUFSIZ];
  636.     char oldmailname[BUFSIZ];
  637.  
  638.     /*
  639.      * Assume we will be in "edit file" mode, until
  640.      * proven wrong.
  641.      */
  642.     *aedit = 1;
  643.     switch (*name) {
  644.     case '%':
  645.         *aedit = 0;
  646.         strcpy(prevfile, mailname);
  647.         if (name[1] != 0) {
  648.             strcpy(savename, myname);
  649.             strcpy(oldmailname, mailname);
  650.             strncpy(myname, name+1, PATHSIZE-1);
  651.             myname[PATHSIZE-1] = 0;
  652.             findmail();
  653.             cp = savestr(mailname);
  654.             strcpy(myname, savename);
  655.             strcpy(mailname, oldmailname);
  656.             return(cp);
  657.         }
  658.         strcpy(oldmailname, mailname);
  659.         findmail();
  660.         cp = savestr(mailname);
  661.         strcpy(mailname, oldmailname);
  662.         return(cp);
  663.  
  664.     case '#':
  665.         if (name[1] != 0)
  666.             goto regular;
  667.         if (prevfile[0] == 0) {
  668.             printf("No previous file\n");
  669.             return(NOSTR);
  670.         }
  671.         cp = savestr(prevfile);
  672.         strcpy(prevfile, mailname);
  673.         return(cp);
  674.  
  675.     case '&':
  676.         strcpy(prevfile, mailname);
  677.         if (name[1] == 0)
  678.             return(mbox);
  679.         /* Fall into . . . */
  680.  
  681.     default:
  682. regular:
  683.         strcpy(prevfile, mailname);
  684.         cp = expand(name);
  685.         return(cp);
  686.     }
  687. }
  688.  
  689. /*
  690.  * Expand file names like echo
  691.  */
  692.  
  693. echo(argv)
  694.     char **argv;
  695. {
  696.     register char **ap;
  697.     register char *cp;
  698.  
  699.     for (ap = argv; *ap != NOSTR; ap++) {
  700.         cp = *ap;
  701.         if ((cp = expand(cp)) != NOSTR)
  702.             printf("%s ", cp);
  703.     }
  704.     return(0);
  705. }
  706.  
  707. /*
  708.  * Reply to a series of messages by simply mailing to the senders
  709.  * and not messing around with the To: and Cc: lists as in normal
  710.  * reply.
  711.  */
  712.  
  713. Respond(msgvec)
  714.     int msgvec[];
  715. {
  716.     struct header head;
  717.     struct message *mp;
  718.     register int s, *ap;
  719.     register char *cp, *cp2, *subject;
  720.  
  721.     for (s = 0, ap = msgvec; *ap != 0; ap++) {
  722.         mp = &message[*ap - 1];
  723.         dot = mp;
  724.         if ((cp = hfield("from", mp)) != NOSTR)
  725.             s+= strlen(cp) + 2;
  726.         else
  727.             s += strlen(nameof(mp, 2)) + 2;
  728.     }
  729.     if (s == 0)
  730.         return(0);
  731.     cp = salloc(s + 2);
  732.     head.h_to = cp;
  733.     for (ap = msgvec; *ap != 0; ap++) {
  734.         mp = &message[*ap - 1];
  735.         if ((cp2 = hfield("from", mp)) == NOSTR)
  736.             cp2 = nameof(mp, 2);
  737.         *cp++ = ' ';
  738.         cp = copy(cp2, cp);
  739.         *cp++ = ',';
  740.     }
  741.     *--cp = 0;
  742.     mp = &message[msgvec[0] - 1];
  743.     subject = hfield("subject", mp);
  744.     head.h_seq = 0;
  745.     if (subject == NOSTR)
  746.         subject = hfield("subj", mp);
  747.     head.h_subject = reedit(subject);
  748.     if (subject != NOSTR)
  749.         head.h_seq++;
  750.     head.h_cc = NOSTR;
  751.     head.h_bcc = NOSTR;
  752.     mail1(&head);
  753.     return(0);
  754. }
  755.  
  756. /*
  757.  * Conditional commands.  These allow one to parameterize one's
  758.  * .mailrc and do some things if sending, others if receiving.
  759.  */
  760.  
  761. ifcmd(argv)
  762.     char **argv;
  763. {
  764.     register char *cp;
  765.  
  766.     if (cond != CANY) {
  767.         printf("Illegal nested \"if\"\n");
  768.         return(1);
  769.     }
  770.     cond = CANY;
  771.     cp = argv[0];
  772.     switch (*cp) {
  773.     case 'r': case 'R':
  774.         cond = CRCV;
  775.         break;
  776.  
  777.     case 's': case 'S':
  778.         cond = CSEND;
  779.         break;
  780.  
  781.     default:
  782.         printf("Unrecognized if-keyword: \"%s\"\n", cp);
  783.         return(1);
  784.     }
  785.     return(0);
  786. }
  787.  
  788. /*
  789.  * Implement 'else'.  This is pretty simple -- we just
  790.  * flip over the conditional flag.
  791.  */
  792.  
  793. elsecmd()
  794. {
  795.  
  796.     switch (cond) {
  797.     case CANY:
  798.         printf("\"Else\" without matching \"if\"\n");
  799.         return(1);
  800.  
  801.     case CSEND:
  802.         cond = CRCV;
  803.         break;
  804.  
  805.     case CRCV:
  806.         cond = CSEND;
  807.         break;
  808.  
  809.     default:
  810.         printf("Mail's idea of conditions is screwed up\n");
  811.         cond = CANY;
  812.         break;
  813.     }
  814.     return(0);
  815. }
  816.  
  817. /*
  818.  * End of if statement.  Just set cond back to anything.
  819.  */
  820.  
  821. endifcmd()
  822. {
  823.  
  824.     if (cond == CANY) {
  825.         printf("\"Endif\" without matching \"if\"\n");
  826.         return(1);
  827.     }
  828.     cond = CANY;
  829.     return(0);
  830. }
  831.  
  832. /*
  833.  * Set the list of alternate names.
  834.  */
  835. alternates(namelist)
  836.     char **namelist;
  837. {
  838.     register int c;
  839.     register char **ap, **ap2, *cp;
  840.  
  841.     c = argcount(namelist) + 1;
  842.     if (c == 1) {
  843.         if (altnames == 0)
  844.             return(0);
  845.         for (ap = altnames; *ap; ap++)
  846.             printf("%s ", *ap);
  847.         printf("\n");
  848.         return(0);
  849.     }
  850.     if (altnames != 0)
  851.         cfree((char *) altnames);
  852.     altnames = (char **) calloc((unsigned) c, sizeof (char *));
  853.     for (ap = namelist, ap2 = altnames; *ap; ap++, ap2++) {
  854.         cp = (char *) calloc((unsigned) (strlen(*ap) + 1),
  855.                      sizeof (char));
  856.         strcpy(cp, *ap);
  857.         *ap2 = cp;
  858.     }
  859.     *ap2 = 0;
  860.     return(0);
  861. }
  862.